package minio

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io"
	"mime/multipart"
	"net/http"
	"oa-rest/common"
	"path/filepath"
	"strings"
	"time"

	"github.com/gin-gonic/gin"
)

// UploadResponse 上传响应
type UploadResponse struct {
	URL      string `json:"url"`
	FileName string `json:"fileName"`
	FileSize int64  `json:"fileSize"`
	Bucket   string `json:"bucket"`
}

// UploadDocumentHandler 上传文档到指定bucket
func UploadDocumentHandler(c *gin.Context) {
	bucketName := c.Param("bucketName")

	// 验证bucket名称
	if !isValidBucket(bucketName) {
		c.JSON(http.StatusBadRequest, gin.H{
			"code":    400,
			"message": "不支持的bucket名称",
			"data":    nil,
		})
		return
	}

	// 获取上传的文件
	file, header, err := c.Request.FormFile("file")
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{
			"code":    400,
			"message": "获取上传文件失败: " + err.Error(),
			"data":    nil,
		})
		return
	}
	defer file.Close()

	// 读取文件内容
	buffer := make([]byte, header.Size)
	_, err = file.Read(buffer)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{
			"code":    500,
			"message": "读取文件内容失败: " + err.Error(),
			"data":    nil,
		})
		return
	}

	// 生成文件名（使用原文件名或自定义文件名）
	customFileName := c.PostForm("fileName")
	fileName := customFileName
	if fileName == "" {
		fileName = header.Filename
	}

	// 可以指定路径前缀
	prefix := c.PostForm("prefix")
	if prefix != "" {
		// 确保prefix以/结尾
		if !strings.HasSuffix(prefix, "/") {
			prefix += "/"
		}
		fileName = prefix + fileName
	}

	// 根据文件扩展名确定Content-Type
	contentType := getContentTypeFromFileName(header.Filename)

	var url string
	var uploadErr error

	// 根据bucket类型上传文件
	switch bucketName {
	case "test":
		url, uploadErr = common.MinioClient.UploadBytesFromMemory(fileName, buffer, contentType)
	case "documents":
		url, uploadErr = common.UploadDocument(fileName, buffer, contentType)
	case "meeting":
		// 如果是音频文件，使用专门的音频上传方法
		if isAudioFile(header.Filename) {
			// 对于音频文件，需要先保存到临时文件再上传
			uploadErr = uploadAudioToMeeting(fileName, buffer, contentType)
		} else {
			url, uploadErr = common.UploadMeeting(fileName, buffer, contentType)
		}
	case "culture":
		// 文化园地文件上传到culture
		url, uploadErr = common.UploadToDynamicBucket(bucketName, fileName, buffer, contentType)
	default:
		// 对于动态bucket（如user-001, user_001等），使用动态bucket上传方法
		url, uploadErr = common.UploadToDynamicBucket(bucketName, fileName, buffer, contentType)
	}

	if uploadErr != nil {
		c.JSON(http.StatusInternalServerError, gin.H{
			"code":    500,
			"message": "文件上传失败: " + uploadErr.Error(),
			"data":    nil,
		})
		return
	}

	c.JSON(http.StatusOK, gin.H{
		"code":    200,
		"message": "文件上传成功",
		"data": UploadResponse{
			URL:      url,
			FileName: fileName,
			FileSize: header.Size,
			Bucket:   bucketName,
		},
	})
}

// UploadAndParseDocumentHandler 上传文档并调用AI服务进行解析
func UploadAndParseDocumentHandler(c *gin.Context) {
	bucketName := c.Param("bucketName")

	// 验证bucket名称
	if bucketName != "documents" {
		c.JSON(http.StatusBadRequest, gin.H{
			"code":    400,
			"message": "文档解析接口只支持 'documents' bucket",
			"data":    nil,
		})
		return
	}

	// 获取上传的文件
	file, header, err := c.Request.FormFile("file")
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{
			"code":    400,
			"message": "获取上传文件失败: " + err.Error(),
			"data":    nil,
		})
		return
	}
	defer file.Close()

	// 读取文件内容
	buffer := make([]byte, header.Size)
	_, err = file.Read(buffer)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{
			"code":    500,
			"message": "读取文件内容失败: " + err.Error(),
			"data":    nil,
		})
		return
	}

	// 生成文件名（使用原文件名或自定义文件名）
	customFileName := c.PostForm("fileName")
	fileName := customFileName
	if fileName == "" {
		fileName = header.Filename
	}

	// 可以指定路径前缀
	prefix := c.PostForm("prefix")
	if prefix != "" {
		// 确保prefix以/结尾
		if !strings.HasSuffix(prefix, "/") {
			prefix += "/"
		}
		fileName = prefix + fileName
	}

	// 根据文件扩展名确定Content-Type
	contentType := getContentTypeFromFileName(header.Filename)

	// 上传文件到MinIO
	url, uploadErr := common.UploadDocument(fileName, buffer, contentType)
	if uploadErr != nil {
		c.JSON(http.StatusInternalServerError, gin.H{
			"code":    500,
			"message": "文件上传失败: " + uploadErr.Error(),
			"data":    nil,
		})
		return
	}

	// 调用本地服务进行文档解析
	localClient := common.LocalQueryHttpClient
	if localClient == nil {
		c.JSON(http.StatusInternalServerError, gin.H{
			"code":    500,
			"message": "本地服务客户端未初始化",
			"data":    nil,
		})
		return
	}

	// 创建一个包含文件的buffer
	body := &bytes.Buffer{}
	writer := multipart.NewWriter(body)

	// 添加文件
	part, err := writer.CreateFormFile("file", header.Filename)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{
			"code":    500,
			"message": "创建表单文件失败: " + err.Error(),
			"data":    nil,
		})
		return
	}
	_, err = io.Copy(part, bytes.NewReader(buffer))
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{
			"code":    500,
			"message": "复制文件数据失败: " + err.Error(),
			"data":    nil,
		})
		return
	}

	writer.Close()

	// 发送请求到本地服务
	localUrl := fmt.Sprintf("%s/documents/upload", localClient.BaseURL)
	req, err := http.NewRequest("POST", localUrl, body)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{
			"code":    500,
			"message": "创建本地服务请求失败: " + err.Error(),
			"data":    nil,
		})
		return
	}

	// 设置请求头
	req.Header.Set("Content-Type", writer.FormDataContentType())

	resp, err := localClient.Client.Do(req)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{
			"code":    500,
			"message": "调用本地服务失败: " + err.Error(),
			"data":    nil,
		})
		return
	}
	defer resp.Body.Close()

	// 读取并解析本地服务响应
	respBody, err := io.ReadAll(resp.Body)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{
			"code":    500,
			"message": "读取本地服务响应失败: " + err.Error(),
			"data":    nil,
		})
		return
	}

	// 解析本地服务响应
	var localResponse map[string]interface{}
	if err := json.Unmarshal(respBody, &localResponse); err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{
			"code":    500,
			"message": "解析本地服务响应失败: " + err.Error(),
			"data":    nil,
		})
		return
	}

	// 返回成功响应
	c.JSON(http.StatusOK, gin.H{
		"code":    200,
		"message": "文件上传并解析成功",
		"data": UploadResponse{
			URL:      url,
			FileName: fileName,
			FileSize: header.Size,
			Bucket:   bucketName,
		},
		"local_response": localResponse,
	})
}

// BatchUploadDocumentsHandler 批量上传文档
func BatchUploadDocumentsHandler(c *gin.Context) {
	bucketName := c.Param("bucketName")

	// 验证bucket名称
	if !isValidBucket(bucketName) {
		c.JSON(http.StatusBadRequest, gin.H{
			"code":    400,
			"message": "不支持的bucket名称",
			"data":    nil,
		})
		return
	}

	// 获取多个上传的文件
	form, err := c.MultipartForm()
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{
			"code":    400,
			"message": "获取表单数据失败: " + err.Error(),
			"data":    nil,
		})
		return
	}

	files := form.File["files"]
	if len(files) == 0 {
		c.JSON(http.StatusBadRequest, gin.H{
			"code":    400,
			"message": "没有找到上传的文件",
			"data":    nil,
		})
		return
	}

	var results []UploadResponse
	var failedFiles []string

	for _, fileHeader := range files {
		file, err := fileHeader.Open()
		if err != nil {
			failedFiles = append(failedFiles, fileHeader.Filename+" (打开失败)")
			continue
		}

		buffer := make([]byte, fileHeader.Size)
		_, err = file.Read(buffer)
		file.Close()

		if err != nil {
			failedFiles = append(failedFiles, fileHeader.Filename+" (读取失败)")
			continue
		}

		fileName := fileHeader.Filename
		prefix := c.PostForm("prefix")
		if prefix != "" {
			if !strings.HasSuffix(prefix, "/") {
				prefix += "/"
			}
			fileName = prefix + fileName
		}

		contentType := getContentTypeFromFileName(fileHeader.Filename)

		var url string
		var uploadErr error

		switch bucketName {
		case "test":
			url, uploadErr = common.MinioClient.UploadBytesFromMemory(fileName, buffer, contentType)
		case "documents":
			url, uploadErr = common.UploadDocument(fileName, buffer, contentType)
		case "meeting":
			if isAudioFile(fileHeader.Filename) {
				uploadErr = uploadAudioToMeeting(fileName, buffer, contentType)
			} else {
				url, uploadErr = common.UploadMeeting(fileName, buffer, contentType)
			}
		case "culture":
			// 文化园地文件上传到culture
			url, uploadErr = common.UploadToDynamicBucket(bucketName, fileName, buffer, contentType)
		default:
			// 对于动态bucket（如user-001, user_001等），使用动态bucket上传方法
			url, uploadErr = common.UploadToDynamicBucket(bucketName, fileName, buffer, contentType)
		}

		if uploadErr != nil {
			failedFiles = append(failedFiles, fileHeader.Filename+" (上传失败: "+uploadErr.Error()+")")
		} else {
			results = append(results, UploadResponse{
				URL:      url,
				FileName: fileName,
				FileSize: fileHeader.Size,
				Bucket:   bucketName,
			})
		}
	}

	response := gin.H{
		"code":    200,
		"message": "批量上传完成",
		"data": gin.H{
			"success": results,
			"failed":  failedFiles,
		},
	}

	c.JSON(http.StatusOK, response)
}

// 辅助函数
func isValidBucket(bucketName string) bool {
	switch bucketName {
	case "test", "documents", "meeting", "culture":
		return true
	default:
		// 对于动态bucket，检查名称是否符合规范
		// 这里可以复用 bucket_handler.go 中的 isValidBucketName 函数
		// 或者简单检查长度和字符
		if len(bucketName) >= 3 && len(bucketName) <= 63 {
			for _, char := range bucketName {
				if !((char >= 'a' && char <= 'z') ||
					(char >= '0' && char <= '9') ||
					char == '-' || char == '_' || char == '.') {
					return false
				}
			}
			// 检查首尾字符
			if bucketName[0] == '-' || bucketName[0] == '_' || bucketName[0] == '.' ||
				bucketName[len(bucketName)-1] == '-' || bucketName[len(bucketName)-1] == '_' || bucketName[len(bucketName)-1] == '.' {
				return false
			}
			return true
		}
		return false
	}
}

func getContentTypeFromFileName(fileName string) string {
	ext := strings.ToLower(filepath.Ext(fileName))
	switch ext {
	case ".pdf":
		return "application/pdf"
	case ".doc", ".docx":
		return "application/msword"
	case ".xls", ".xlsx":
		return "application/vnd.ms-excel"
	case ".ppt", ".pptx":
		return "application/vnd.ms-powerpoint"
	case ".txt":
		return "text/plain"
	case ".md":
		return "text/markdown"
	case ".jpg", ".jpeg":
		return "image/jpeg"
	case ".png":
		return "image/png"
	case ".gif":
		return "image/gif"
	case ".mp3":
		return "audio/mpeg"
	case ".wav":
		return "audio/wav"
	case ".m4a":
		return "audio/mp4"
	case ".mp4":
		return "video/mp4"
	case ".zip":
		return "application/zip"
	default:
		return "application/octet-stream"
	}
}

func isAudioFile(fileName string) bool {
	ext := strings.ToLower(filepath.Ext(fileName))
	switch ext {
	case ".mp3", ".wav", ".m4a", ".ogg", ".flac":
		return true
	default:
		return false
	}
}

func uploadAudioToMeeting(fileName string, buffer []byte, contentType string) error {
	// 由于UploadAudioFile需要文件路径，这里暂时使用UploadMeeting方法
	// 如果需要支持内存中的音频文件上传，可以扩展common包
	_, err := common.UploadMeeting(fileName, buffer, contentType)
	return err
}

// ParseStatus 解析状态结构
type ParseStatus struct {
	FileName     string  `json:"fileName"`
	Status       string  `json:"status"`       // pending, processing, completed, failed
	Progress     float64 `json:"progress"`     // 0-100
	Message      string  `json:"message"`      // 状态描述
	ParsedText   string  `json:"parsedText"`   // 解析的文本内容（完成时）
	ErrorMessage string  `json:"errorMessage"` // 错误信息（失败时）
	CreatedAt    string  `json:"createdAt"`    // 创建时间
	UpdatedAt    string  `json:"updatedAt"`    // 更新时间
}

// 模拟的解析状态存储（实际项目中应该使用数据库或缓存）
var parseStatusMap = make(map[string]*ParseStatus)

// GetParseStatusHandler 获取文档解析状态
func GetParseStatusHandler(c *gin.Context) {
	bucketName := c.Param("bucketName")
	fileName := c.Param("fileName")

	// 验证bucket名称
	if bucketName != "documents" {
		c.JSON(http.StatusBadRequest, gin.H{
			"code":    400,
			"message": "进度查询只支持 'documents' bucket",
			"data":    nil,
		})
		return
	}

	// 获取解析状态
	status, exists := parseStatusMap[fileName]
	if !exists {
		// 如果不存在状态记录，尝试查询AI服务获取实际状态
		status = checkAIStatus(fileName)
	}

	c.JSON(http.StatusOK, gin.H{
		"code":    200,
		"message": "获取解析状态成功",
		"data":    status,
	})
}

// checkAIStatus 检查AI服务中的文档状态
func checkAIStatus(fileName string) *ParseStatus {
	aiClient := common.DocQAHttpClient
	if aiClient == nil {
		return &ParseStatus{
			FileName:     fileName,
			Status:       "failed",
			Progress:     0,
			Message:      "AI服务未初始化",
			ErrorMessage: "DocQAHttpClient is nil",
			CreatedAt:    timeNow(),
			UpdatedAt:    timeNow(),
		}
	}

	// 构建请求数据
	requestData := map[string]interface{}{
		"file_name": fileName,
		"action":    "check_status",
	}

	// 调用AI服务查询状态
	var response map[string]interface{}
	url := fmt.Sprintf("%s/documents/status", aiClient.BaseURL)

	req, err := http.NewRequest("POST", url, bytes.NewBuffer(jsonEncode(requestData)))
	if err != nil {
		return createFailedStatus(fileName, "创建请求失败: "+err.Error())
	}

	req.Header.Set("Content-Type", "application/json")
	req.Header.Set("Accept", "application/json")

	resp, err := aiClient.Client.Do(req)
	if err != nil {
		return createFailedStatus(fileName, "调用AI服务失败: "+err.Error())
	}
	defer resp.Body.Close()

	body, err := io.ReadAll(resp.Body)
	if err != nil {
		return createFailedStatus(fileName, "读取响应失败: "+err.Error())
	}

	// 解析响应
	if err := json.Unmarshal(body, &response); err != nil {
		return createFailedStatus(fileName, "解析响应失败: "+err.Error())
	}

	// 根据AI服务响应构建状态
	return buildStatusFromAIResponse(fileName, response)
}

// createFailedStatus 创建失败状态
func createFailedStatus(fileName, errorMsg string) *ParseStatus {
	return &ParseStatus{
		FileName:     fileName,
		Status:       "failed",
		Progress:     0,
		Message:      "解析失败",
		ErrorMessage: errorMsg,
		CreatedAt:    timeNow(),
		UpdatedAt:    timeNow(),
	}
}

// buildStatusFromAIResponse 根据AI响应构建状态
func buildStatusFromAIResponse(fileName string, aiResponse map[string]interface{}) *ParseStatus {
	status := &ParseStatus{
		FileName:  fileName,
		CreatedAt: timeNow(),
		UpdatedAt: timeNow(),
	}

	// 解析AI服务响应
	if statusStr, ok := aiResponse["status"].(string); ok {
		switch statusStr {
		case "processing":
			status.Status = "processing"
			status.Progress = 50.0
			status.Message = "正在解析文档..."
		case "completed":
			status.Status = "completed"
			status.Progress = 100.0
			status.Message = "解析完成"
			if parsedText, ok := aiResponse["parsed_text"].(string); ok {
				status.ParsedText = parsedText
			}
		case "failed":
			status.Status = "failed"
			status.Progress = 0
			status.Message = "解析失败"
			if errorMsg, ok := aiResponse["error"].(string); ok {
				status.ErrorMessage = errorMsg
			}
		default:
			status.Status = "pending"
			status.Progress = 0
			status.Message = "等待解析"
		}
	} else {
		// 如果AI服务返回Not Found或其他错误
		status.Status = "failed"
		status.Progress = 0
		status.Message = "AI服务不可用"
		if detail, ok := aiResponse["detail"].(string); ok {
			status.ErrorMessage = detail
		} else {
			status.ErrorMessage = "无法连接到AI服务"
		}
	}

	return status
}

// timeNow 获取当前时间的字符串表示
func timeNow() string {
	return time.Now().Format("2006-01-02 15:04:05")
}

// jsonEncode JSON编码辅助函数
func jsonEncode(data interface{}) []byte {
	result, _ := json.Marshal(data)
	return result
}
